package n18_犹豫模式_在n17基础上优化;

/**
 * @author fu
 * @date 2022-01-16 20:42
 * 概要：
 * --------------------------------------------------------
 * |                                                      |
 * |      Balking 犹豫模式 ：如果执行了 就不再重复执行         |
 * |                                                      |
 * |=======================================================
 *             // 以下有多行语句，涉及了 读 和 写 ；所以不是可见性 还要保证原子性
 *             if(starting){
 *                 return ;
 *             }else{
 *                 starting = true;
 *             }
 */

import lombok.extern.slf4j.Slf4j;

import static utils.Sleeper.sleep;

/**
 * 两阶段终止 设计模式
 */
@Slf4j(topic = "c.T7")
public class T1_interrupt_twoPhaseTermination {

    public static void main(String[] args) {

        log.debug("开始。。。");
        final TwoPhaseTermination tpt = new TwoPhaseTermination();
        // 1. 开始 监控线程
        tpt.start();
        tpt.start();
        tpt.start();

        // 2. 主线程 睡眠
        sleep(13);

        // 3. 终止 监控线程
        tpt.stop();
    }

}

@Slf4j(topic = "c.TwoPhaseTermination")
class TwoPhaseTermination{

    // 监控线程
    private Thread monitor;

    private volatile boolean stop = false; // 【虽然 不加volatile也能停止！是因为 debug和 sleep都会保证可见性！】

    // 只让 start()执行一次; 不能仅仅用volatile 防止还未来得及改 两个线程进来了，所以要synchronize
    private volatile boolean starting = false;

    /*------------------------------------------------------------------
    |                                                                  |
    |            犹豫模式 ：如果执行了 就不再重复执行                       |
    |                                                                  |
    |==================================================================*/
    // 启动 监控线程
    public void start(){

        synchronized (this) {
            // 以下有多行语句，涉及了 读 和 写 ；所以不是可见性 还要保证原子性
            if(starting){
                return ;
            }else{
                starting = true;
            }

        } // 【--- synchronized 代码块包含的代码 越少越利于性能提升 ---】

        monitor = new Thread(()->{
            while (true){
                final Thread current = Thread.currentThread();
                if(stop){
                    log.debug("线程被打断.... 料理后事......");
                    break;
                }

                try {
                    Thread.sleep(5000);    // 1. 这里被打断 interrupt=false
                    log.debug("执行监控记录。。。");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

        });
        monitor.start();
    }


    // 停止 监控线程
    public void stop(){
        log.debug("修改 sotp=true");
        stop=true;
        monitor.interrupt(); // 不让 睡眠，让修改状态立即生效
    }



}
